home *** CD-ROM | disk | FTP | other *** search
/ Celestin Apprentice 7 / Apprentice-Release7.iso / Source Code / C / Applications / Tcl-Tk 8.0 / Pre-installed version / MoreFiles 1.4.3 / Sources / MoreDesktopMgr.c < prev    next >
Encoding:
C/C++ Source or Header  |  1996-08-24  |  30.0 KB  |  1,149 lines  |  [TEXT/MPS ]

  1. /*
  2. **    Apple Macintosh Developer Technical Support
  3. **
  4. **    A collection of useful high-level Desktop Manager routines.
  5. **    If the Desktop Manager isn't available, use the Desktop file
  6. **    for 'read' operations.
  7. **
  8. **    We do more because we can...
  9. **
  10. **    by Jim Luther and Nitin Ganatra, Apple Developer Technical Support Emeriti
  11. **
  12. **    File:    MoreDesktopMgr.c
  13. **
  14. **    Copyright © 1992-1996 Apple Computer, Inc.
  15. **    All rights reserved.
  16. **
  17. **    You may incorporate this sample code into your applications without
  18. **    restriction, though the sample code has been provided "AS IS" and the
  19. **    responsibility for its operation is 100% yours.  However, what you are
  20. **    not permitted to do is to redistribute the source as "DSC Sample Code"
  21. **    after having made changes. If you're going to re-distribute the source,
  22. **    we require that you make it clear in the source that the code was
  23. **    descended from Apple Sample Code, but that you've made changes.
  24. */
  25.  
  26. #include <Types.h>
  27. #include <Errors.h>
  28. #include <Memory.h>
  29. #include <Files.h>
  30. #include <Resources.h>
  31. #include <Icons.h>
  32.  
  33. #define    __COMPILINGMOREFILES
  34.  
  35. #include "MoreFiles.h"
  36. #include "MoreFilesExtras.h"
  37. #include "Search.h"
  38. #include "MoreDesktopMgr.h"
  39.  
  40. /*****************************************************************************/
  41.  
  42. /*    Desktop file notes:
  43. **
  44. **    •    The Desktop file is owned by the Finder and is normally open by the
  45. **        Finder. That means that we only have read-only access to the Desktop
  46. **        file.
  47. **    •    Since the Resource Manager doesn't support shared access to resource
  48. **        files and we're using read-only access, we don't ever leave the
  49. **        Desktop file open.  We open a path to it, get the data we want out
  50. **        of it, and then close the open path. This is the only safe way to
  51. **        open a resource file with read-only access since some other program
  52. **        could have it open with write access.
  53. **    •    The bundle related resources in the Desktop file are normally
  54. **        purgable, so when we're looking through them, we don't bother to
  55. **        release resources we're done looking at - closing the resource file
  56. **        (which we always do) will release them.
  57. **    •    Since we can't assume the Desktop file is named "Desktop"
  58. **        (it probably is everywhere but France), we get the Desktop
  59. **        file's name by searching the volume's root directory for a file
  60. **        with fileType == 'FNDR' and creator == 'ERIK'. The only problem with
  61. **        this scheme is that someone could create another file with that type
  62. **        and creator in the root directory and we'd find the wrong file.
  63. **        The chances of this are very slim.
  64. */
  65.  
  66. /*****************************************************************************/
  67.  
  68. /* local defines */
  69.  
  70. enum
  71. {
  72.     kBNDLResType    = 'BNDL',
  73.     kFREFResType    = 'FREF',
  74.     kIconFamResType    = 'ICN#',
  75.     kFCMTResType    = 'FCMT',
  76.     kAPPLResType    = 'APPL'
  77. };
  78.  
  79. /*****************************************************************************/
  80.  
  81. /* local data structures */
  82.  
  83. #if PRAGMA_ALIGN_SUPPORTED
  84. #pragma options align=mac68k
  85. #endif
  86.  
  87. struct IDRec
  88. {
  89.     short        localID;
  90.     short        rsrcID;
  91. };
  92. typedef struct IDRec IDRec;
  93. typedef    IDRec *IDRecPtr;
  94.  
  95. struct BundleType
  96. {
  97.     OSType        type;            /* 'ICN#' or 'FREF' */
  98.     short        count;            /* number of IDRecs - 1 */
  99.     IDRec        idArray[1];
  100. };
  101. typedef struct BundleType BundleType;
  102. typedef BundleType *BundleTypePtr;
  103.  
  104. struct BNDLRec
  105. {
  106.     OSType        signature;        /* creator type signature */
  107.     short        versionID;        /* version - should always be 0 */
  108.     short        numTypes;        /* number of elements in typeArray - 1 */
  109.     BundleType    typeArray[1];
  110. };
  111. typedef struct BNDLRec BNDLRec;
  112. typedef BNDLRec **BNDLRecHandle;
  113.  
  114. struct FREFRec
  115. {
  116.     OSType        fileType;        /* file type */
  117.     short        iconID;            /* icon local ID */
  118.     Str255        fileName;        /* file name */
  119. };
  120. typedef struct FREFRec FREFRec;
  121. typedef FREFRec **FREFRecHandle;
  122.  
  123. struct APPLRec
  124. {
  125.     OSType        creator;        /* creator type signature */
  126.     long        parID;            /* parent directory ID */
  127.     Str255        applName;        /* application name */
  128. };
  129. typedef struct APPLRec APPLRec;
  130. typedef APPLRec *APPLRecPtr;
  131.  
  132. #if PRAGMA_ALIGN_SUPPORTED
  133. #pragma options align=reset
  134. #endif
  135.  
  136. /*****************************************************************************/
  137.  
  138. /* static prototypes */
  139.  
  140. static    OSErr    GetDesktopFileName(short vRefNum,
  141.                                    Str255 desktopName);
  142.  
  143. static    OSErr    GetAPPLFromDesktopFile(StringPtr volName,
  144.                                        short vRefNum,
  145.                                        OSType creator,
  146.                                        short *applVRefNum,
  147.                                        long *applParID,
  148.                                        Str255 applName);
  149.  
  150. static    OSErr    FindBundleGivenCreator(OSType creator,
  151.                                        BNDLRecHandle *returnBndl);
  152.                                        
  153. static    OSErr    FindTypeInBundle(OSType typeToFind,
  154.                                  BNDLRecHandle theBndl,
  155.                                  BundleTypePtr *returnBundleType);
  156.                                          
  157. static    OSErr    GetLocalIDFromFREF(BundleTypePtr theBundleType,
  158.                                    OSType fileType,
  159.                                    short *iconLocalID);
  160.  
  161. static    OSErr    GetIconRsrcIDFromLocalID(BundleTypePtr theBundleType,
  162.                                          short iconLocalID,
  163.                                          short *iconRsrcID);
  164.  
  165. static    OSType    DTIconToResIcon(short iconType);
  166.  
  167. static    OSErr    GetIconFromDesktopFile(StringPtr volName,
  168.                                        short vRefNum,
  169.                                        short iconType,
  170.                                        OSType fileCreator,
  171.                                        OSType fileType,
  172.                                        Handle *iconHandle);
  173.  
  174. static    OSErr    GetCommentID(short vRefNum,
  175.                              long dirID,
  176.                              StringPtr name,
  177.                              short *commentID);
  178.  
  179. static    OSErr    GetCommentFromDesktopFile(short vRefNum,
  180.                                           long dirID,
  181.                                           StringPtr name,
  182.                                           Str255 comment);
  183.  
  184. /*****************************************************************************/
  185.  
  186. /*
  187. **    GetDesktopFileName
  188. **
  189. **    Get the name of the Desktop file.
  190. */
  191. static    OSErr    GetDesktopFileName(short vRefNum,
  192.                                    Str255 desktopName)
  193. {
  194.     OSErr            error;
  195.     HParamBlockRec    pb;
  196.     short            index;
  197.     Boolean            found = false;
  198.     
  199.     pb.fileParam.ioNamePtr = desktopName;
  200.     pb.fileParam.ioVRefNum = vRefNum;
  201.     pb.fileParam.ioFVersNum = 0;
  202.     index = 1;
  203.     do
  204.     {
  205.         pb.fileParam.ioDirID = fsRtDirID;
  206.         pb.fileParam.ioFDirIndex = index;
  207.         error = PBHGetFInfoSync(&pb);
  208.         if ( error == noErr )
  209.         {
  210.             if ( (pb.fileParam.ioFlFndrInfo.fdType == 'FNDR') &&
  211.                  (pb.fileParam.ioFlFndrInfo.fdCreator == 'ERIK') )
  212.             {
  213.                 found = true;
  214.             }
  215.         }
  216.         ++index;
  217.     } while ( (error == noErr) && !found );
  218.     
  219.     return ( error );
  220. }
  221.  
  222. /*****************************************************************************/
  223.  
  224. pascal    OSErr    DTOpen(StringPtr volName,
  225.                        short vRefNum,
  226.                        short *dtRefNum,
  227.                        Boolean *newDTDatabase)
  228. {
  229.     OSErr error;
  230.     GetVolParmsInfoBuffer volParmsInfo;
  231.     long infoSize;
  232.     DTPBRec pb;
  233.     
  234.     /* Check for volume Desktop Manager support before calling */
  235.     infoSize = sizeof(GetVolParmsInfoBuffer);
  236.     error = HGetVolParms(volName, vRefNum, &volParmsInfo, &infoSize);
  237.     if ( error == noErr )
  238.     {
  239.         if ( hasDesktopMgr(volParmsInfo) )
  240.         {
  241.             pb.ioNamePtr = volName;
  242.             pb.ioVRefNum = vRefNum;
  243.             error = PBDTOpenInform(&pb);
  244.             /* PBDTOpenInform informs us if the desktop was just created */
  245.             /* by leaving the low bit of ioTagInfo clear (0) */
  246.             *newDTDatabase = ((pb.ioTagInfo & 1L) == 0);
  247.             if ( error == paramErr )
  248.             {
  249.                 error = PBDTGetPath(&pb);
  250.                 /* PBDTGetPath doesn't tell us if the database is new */
  251.                 /* so assume it is not new */
  252.                 *newDTDatabase = false;
  253.             }
  254.             *dtRefNum = pb.ioDTRefNum;
  255.         }
  256.         else
  257.             error = paramErr;
  258.     }
  259.     return ( error );
  260. }
  261.  
  262. /*****************************************************************************/
  263.  
  264. /*
  265. **    GetAPPLFromDesktopFile
  266. **
  267. **    Get a application's location from the
  268. **    Desktop file's 'APPL' resources.
  269. */
  270. static    OSErr    GetAPPLFromDesktopFile(StringPtr volName,
  271.                                        short vRefNum,
  272.                                        OSType creator,
  273.                                        short *applVRefNum,
  274.                                        long *applParID,
  275.                                        Str255 applName)
  276. {
  277.     OSErr error;
  278.     short realVRefNum;
  279.     Str255 desktopName;
  280.     short savedResFile;
  281.     short dfRefNum;
  282.     Handle applResHandle;
  283.     Boolean foundCreator;
  284.     Ptr applPtr;
  285.     long applSize;
  286.     
  287.     error = DetermineVRefNum(volName, vRefNum, &realVRefNum);
  288.     if ( error == noErr )
  289.     {
  290.         error = GetDesktopFileName(realVRefNum, desktopName);
  291.         if ( error == noErr )
  292.         {
  293.             savedResFile = CurResFile();
  294.             /*
  295.             **    Open the 'Desktop' file in the root directory. (because
  296.             **    opening the resource file could preload unwanted resources,
  297.             **    bracket the call with SetResLoad(s))
  298.             */
  299.             SetResLoad(false);
  300.             dfRefNum = HOpenResFile(realVRefNum, fsRtDirID, desktopName, fsRdPerm);
  301.             SetResLoad(true);
  302.             
  303.             if ( dfRefNum != -1)
  304.             {
  305.                 /* Get 'APPL' resource ID 0 */
  306.                 applResHandle = Get1Resource(kAPPLResType, 0);
  307.                 if ( applResHandle != NULL )
  308.                 {
  309.                     applSize = GetHandleSize((Handle)applResHandle);
  310.                     if ( applSize != 0 )    /* make sure the APPL resource isn't empty */
  311.                     {
  312.                         foundCreator = false;
  313.                         applPtr = *applResHandle;
  314.                         
  315.                         /* APPL's don't have a count so I have to use the size as the bounds */
  316.                         while ( (foundCreator == false) &&
  317.                                 (applPtr < (*applResHandle + applSize)) )
  318.                         {
  319.                             if ( ((APPLRecPtr)applPtr)->creator == creator )
  320.                             {
  321.                                 foundCreator = true;
  322.                             }
  323.                             else
  324.                             {
  325.                                 /* fun with pointer math... */
  326.                                 applPtr += sizeof(OSType) +
  327.                                            sizeof(long) +
  328.                                            ((APPLRecPtr)applPtr)->applName[0] + 1;
  329.                                 /* application mappings are word aligned within the resource */
  330.                                 if ( ((unsigned long)applPtr % 2) != 0 )
  331.                                     applPtr += 1;
  332.                             }
  333.                         }
  334.                         if ( foundCreator == true )
  335.                         {
  336.                             *applVRefNum = realVRefNum;
  337.                             *applParID = ((APPLRecPtr)applPtr)->parID;
  338.                             BlockMoveData(((APPLRecPtr)applPtr)->applName,
  339.                                           applName,
  340.                                           ((APPLRecPtr)applPtr)->applName[0] + 1);
  341.                             error = noErr;
  342.                         }
  343.                     }
  344.                     else
  345.                         error = afpItemNotFound;    /* no APPL mapping available */
  346.                 }
  347.                 else
  348.                     error = afpItemNotFound;    /* no APPL mapping available */
  349.                 
  350.                 /* restore the resource chain and close the Desktop file */
  351.                 UseResFile(savedResFile);
  352.                 CloseResFile(dfRefNum);
  353.             }
  354.             else
  355.                 error = afpItemNotFound;
  356.         }
  357.     }
  358.     return ( error );
  359. }
  360.  
  361. /*****************************************************************************/
  362.  
  363. pascal    OSErr    DTGetAPPL(StringPtr volName,
  364.                           short vRefNum,
  365.                           OSType creator,
  366.                           short *applVRefNum,
  367.                           long *applParID,
  368.                           Str255 applName)
  369. {
  370.     OSErr error;
  371.     UniversalFMPB pb;
  372.     short dtRefNum;
  373.     Boolean newDTDatabase;
  374.     short realVRefNum;
  375.     short index;
  376.     Boolean applFound;
  377.     FSSpec spec;
  378.     long actMatchCount;
  379.     
  380.     /* get the real vRefNum */
  381.     error = DetermineVRefNum(volName, vRefNum, &realVRefNum);
  382.     if ( error == noErr )
  383.     {
  384.         error = DTOpen(volName, vRefNum, &dtRefNum, &newDTDatabase);
  385.         if ( error == noErr )
  386.         {
  387.             if ( !newDTDatabase )
  388.             {
  389.                 index = 0;
  390.                 applFound = false;
  391.                 do
  392.                 {
  393.                     pb.dtPB.ioNamePtr = applName;
  394.                     pb.dtPB.ioDTRefNum = dtRefNum;
  395.                     pb.dtPB.ioIndex = index;
  396.                     pb.dtPB.ioFileCreator = creator;
  397.                     error = PBDTGetAPPLSync(&pb.dtPB);
  398.                     if ( error == noErr )
  399.                     {
  400.                         /* got a match - see if it is valid */
  401.                         
  402.                         *applVRefNum = realVRefNum; /* get the vRefNum now */
  403.                         *applParID = pb.dtPB.ioAPPLParID; /* get the parent ID now */
  404.     
  405.                         /* pb.hPB.fileParam.ioNamePtr is already set */
  406.                         pb.hPB.fileParam.ioVRefNum = realVRefNum;
  407.                         pb.hPB.fileParam.ioFVersNum = 0;
  408.                         pb.hPB.fileParam.ioDirID = *applParID;
  409.                         pb.hPB.fileParam.ioFDirIndex = 0;    /* use ioNamePtr and ioDirID */
  410.                         if ( PBHGetFInfoSync(&pb.hPB) == noErr )
  411.                         {
  412.                             if ( (pb.hPB.fileParam.ioFlFndrInfo.fdCreator == creator) &&
  413.                                  (pb.hPB.fileParam.ioFlFndrInfo.fdType == 'APPL') )
  414.                             {
  415.                                 applFound = true;
  416.                             }
  417.                         }
  418.                     }
  419.                     ++index;
  420.                 } while ( (error == noErr) && !applFound );
  421.                 if ( error != noErr )
  422.                     error = afpItemNotFound;
  423.             }
  424.             else
  425.                 /* Desktop database is empty (new), set error to try CatSearch */
  426.                 error = afpItemNotFound;
  427.         }
  428.         /* acceptable errors from Desktop Manager to continue are paramErr or afpItemNotFound */
  429.         if ( error == paramErr )
  430.         {
  431.             /* if paramErr, the volume didn't support the Desktop Manager */
  432.             /* try the Desktop file */
  433.             
  434.             error = GetAPPLFromDesktopFile(volName, vRefNum, creator,
  435.                                             applVRefNum, applParID, applName);
  436.             if ( error == noErr )
  437.             {
  438.                 /* got a match - see if it is valid */
  439.                 
  440.                 pb.hPB.fileParam.ioNamePtr = applName;
  441.                 pb.hPB.fileParam.ioVRefNum = *applVRefNum;
  442.                 pb.hPB.fileParam.ioFVersNum = 0;
  443.                 pb.hPB.fileParam.ioDirID = *applParID;
  444.                 pb.hPB.fileParam.ioFDirIndex = 0;    /* use ioNamePtr and ioDirID */
  445.                 if ( PBHGetFInfoSync(&pb.hPB) == noErr )
  446.                 {
  447.                     if ( (pb.hPB.fileParam.ioFlFndrInfo.fdCreator != creator) ||
  448.                          (pb.hPB.fileParam.ioFlFndrInfo.fdType != 'APPL') )
  449.                     {
  450.                         error = afpItemNotFound;
  451.                     }
  452.                 }
  453.                 else if ( error == fnfErr )
  454.                     error = afpItemNotFound;
  455.             }
  456.         }
  457.         /* acceptable error from DesktopFile code to continue is afpItemNotFound */
  458.         if ( error == afpItemNotFound )
  459.         {
  460.             /* Couldn't be found in the Desktop file either, try searching with CatSearch */
  461.             
  462.             error = CreatorTypeFileSearch(NULL, realVRefNum, creator, kAPPLResType, &spec, 1,
  463.                                             &actMatchCount, true);
  464.             if ( (error == noErr) || (error == eofErr) )
  465.             {
  466.                 if ( actMatchCount > 0 )
  467.                 {
  468.                     *applVRefNum = spec.vRefNum;
  469.                     *applParID = spec.parID;
  470.                     BlockMoveData(spec.name, applName, spec.name[0] + 1);
  471.                 }
  472.                 else
  473.                     error = afpItemNotFound;
  474.             }
  475.         }
  476.     }
  477.     return ( error );
  478. }
  479.  
  480. /*****************************************************************************/
  481.  
  482. pascal    OSErr    FSpDTGetAPPL(StringPtr volName,
  483.                              short vRefNum,
  484.                              OSType creator,
  485.                              FSSpec *spec)
  486. {
  487.     return ( DTGetAPPL(volName, vRefNum, creator,
  488.                         &(spec->vRefNum), &(spec->parID), spec->name) );
  489. }
  490.  
  491. /*****************************************************************************/
  492.  
  493. /*
  494. **    FindBundleGivenCreator
  495. **
  496. **    Search the current resource file for the 'BNDL' resource with the given
  497. **    creator and return a handle to it.
  498. */
  499. static    OSErr    FindBundleGivenCreator(OSType creator,
  500.                                        BNDLRecHandle *returnBndl)
  501. {
  502.     OSErr            error;
  503.     short            numOfBundles;
  504.     short            index;
  505.     BNDLRecHandle    theBndl;
  506.     
  507.     error = afpItemNotFound;    /* default to not found */
  508.     
  509.     /* Search each BNDL resource until we find the one with a matching creator. */
  510.     
  511.     numOfBundles = Count1Resources(kBNDLResType);
  512.     index = 1;
  513.     *returnBndl = NULL;
  514.     
  515.     while ( (index <= numOfBundles) && (*returnBndl == NULL) )
  516.     {
  517.         theBndl = (BNDLRecHandle)Get1IndResource(kBNDLResType, index);
  518.         
  519.         if ( theBndl != NULL )
  520.         {
  521.             if ( (*theBndl)->signature == creator )
  522.             {
  523.                 /* numTypes and typeArray->count will always be the actual count minus 1, */
  524.                 /* so 0 in both fields is valid. */
  525.                 if ( ((*theBndl)->numTypes >= 0) && ((*theBndl)->typeArray->count >= 0) )
  526.                 {
  527.                     /* got it */
  528.                     *returnBndl = theBndl;
  529.                     error = noErr;
  530.                 }
  531.             }
  532.         }    
  533.         
  534.         index ++;
  535.     }
  536.     
  537.     return ( error );
  538. }
  539.  
  540. /*****************************************************************************/
  541.  
  542. /*
  543. **    FindTypeInBundle
  544. **
  545. **    Given a Handle to a BNDL return a pointer to the desired type
  546. **    in it. If the type is not found, or if the type's count < 0,
  547. **    return afpItemNotFound.
  548. */
  549. static    OSErr    FindTypeInBundle(OSType typeToFind,
  550.                                  BNDLRecHandle theBndl,
  551.                                  BundleTypePtr *returnBundleType)
  552. {
  553.     OSErr            error;
  554.     short            index;
  555.     Ptr                ptrIterator;    /* use a Ptr so we can do ugly pointer math */
  556.     
  557.     error = afpItemNotFound;    /* default to not found */
  558.     
  559.     ptrIterator = (Ptr)((*theBndl)->typeArray);
  560.     index = 0;
  561.     *returnBundleType = NULL;
  562.  
  563.     while ( (index < ((*theBndl)->numTypes + 1)) &&
  564.             (*returnBundleType == NULL) )
  565.     {
  566.         if ( (((BundleTypePtr)ptrIterator)->type == typeToFind) &&
  567.              (((BundleTypePtr)ptrIterator)->count >= 0) )
  568.         {
  569.                 *returnBundleType = (BundleTypePtr)ptrIterator;
  570.                 error = noErr;
  571.         }
  572.         else
  573.         {
  574.             ptrIterator += ( sizeof(OSType) +
  575.                              sizeof(short) +
  576.                              ( sizeof(IDRec) * (((BundleTypePtr)ptrIterator)->count + 1) ) );
  577.             ++index;
  578.         }
  579.     }
  580.         
  581.     return ( error );
  582. }
  583.  
  584. /*****************************************************************************/
  585.  
  586. /*
  587. **    GetLocalIDFromFREF
  588. **
  589. **    Given a pointer to a 'FREF' BundleType record, load each 'FREF' resource
  590. **    looking for a matching fileType. If a matching fileType is found, return
  591. **    its icon local ID. If no match is found, return afpItemNotFound as the
  592. **    function result.
  593. */
  594. static    OSErr    GetLocalIDFromFREF(BundleTypePtr theBundleType,
  595.                                    OSType fileType,
  596.                                    short *iconLocalID)
  597. {
  598.     OSErr            error;
  599.     short            index;
  600.     IDRecPtr        idIterator;
  601.     FREFRecHandle    theFref;
  602.     
  603.     error = afpItemNotFound;    /* default to not found */
  604.     
  605.     /* For each localID in this type, get the FREF resource looking for fileType */
  606.     index = 0;
  607.     idIterator = &theBundleType->idArray[0];
  608.     *iconLocalID = 0;
  609.     
  610.     while ( (index <= (theBundleType->count + 1)) && (*iconLocalID == 0) )
  611.     {
  612.         theFref = (FREFRecHandle)Get1Resource(kFREFResType, idIterator->rsrcID);
  613.         if ( theFref != NULL )
  614.         {
  615.             if ( (*theFref)->fileType == fileType )
  616.             {
  617.                 *iconLocalID = (*theFref)->iconID;
  618.                 error = noErr;
  619.             }
  620.         }
  621.         
  622.         ++idIterator;
  623.         ++index;
  624.     }
  625.     
  626.     return ( error );
  627. }
  628.  
  629. /*****************************************************************************/
  630.  
  631. /*
  632. **    GetIconRsrcIDFromLocalID
  633. **
  634. **    Given a pointer to a 'ICN#' BundleType record, look for the IDRec with
  635. **    the localID that matches iconLocalID. If a matching IDRec is found,
  636. **    return the IDRec's rsrcID field value. If no match is found, return
  637. **    afpItemNotFound as the function result.
  638. */
  639. static    OSErr    GetIconRsrcIDFromLocalID(BundleTypePtr theBundleType,
  640.                                          short iconLocalID,
  641.                                          short *iconRsrcID)
  642. {
  643.     OSErr        error;
  644.     short        index;
  645.     IDRecPtr    idIterator;
  646.     
  647.     error = afpItemNotFound;    /* default to not found */
  648.     
  649.     /* Find the rsrcID of the icon family type, given the localID */
  650.     index = 0;
  651.     idIterator = &theBundleType->idArray[0];
  652.     *iconRsrcID = 0;
  653.     
  654.     while ( (index <= (theBundleType->count+1)) && (*iconRsrcID == 0) )
  655.     {
  656.         if ( idIterator->localID == iconLocalID )
  657.         {
  658.             *iconRsrcID = idIterator->rsrcID;
  659.             error = noErr;
  660.         }
  661.         
  662.         idIterator ++;
  663.         index ++;
  664.     }
  665.     
  666.     return ( error );
  667. }
  668.  
  669. /*****************************************************************************/
  670.  
  671. /*
  672. **    DTIconToResIcon
  673. **
  674. **    Map a Desktop Manager icon type to the corresponding resource type.
  675. **    Return (OSType)0 if there is no corresponding resource type.
  676. */
  677. static    OSType    DTIconToResIcon(short iconType)
  678. {
  679.     OSType    resType;
  680.     
  681.     switch ( iconType )
  682.     {
  683.         case kLargeIcon:
  684.             resType = large1BitMask;
  685.             break;
  686.         case kLarge4BitIcon:
  687.             resType = large4BitData;
  688.             break;
  689.         case kLarge8BitIcon:
  690.             resType = large8BitData;
  691.             break;
  692.         case kSmallIcon:
  693.             resType = small1BitMask;
  694.             break;
  695.         case kSmall4BitIcon:
  696.             resType = small4BitData;
  697.             break;
  698.         case kSmall8BitIcon:
  699.             resType = small8BitData;
  700.             break;
  701.         default:
  702.             resType = (OSType)0;
  703.             break;
  704.     }
  705.     
  706.     return ( resType );
  707. }
  708.  
  709. /*****************************************************************************/
  710.  
  711. /*
  712. **    GetIconFromDesktopFile
  713. **
  714. **    INPUT a pointer to a non-existent Handle, because we'll allocate one
  715. **
  716. **    search each BNDL resource for the right fileCreator and once we get it
  717. **        find the 'FREF' type in BNDL
  718. **        for each localID in the type, open the FREF resource
  719. **            if the FREF is the desired fileType
  720. **                get its icon localID
  721. **                get the ICN# type in BNDL
  722. **                get the icon resource number from the icon localID
  723. **                get the icon resource type from the desktop mgr's iconType
  724. **                get the icon of that type and number
  725. */
  726. static    OSErr    GetIconFromDesktopFile(StringPtr volName,
  727.                                        short vRefNum,
  728.                                        short iconType,
  729.                                        OSType fileCreator,
  730.                                        OSType fileType,
  731.                                        Handle *iconHandle)
  732. {
  733.     OSErr            error;
  734.     short            realVRefNum;
  735.     Str255            desktopName;
  736.     short            savedResFile;
  737.     short            dfRefNum;
  738.     BNDLRecHandle    theBndl = NULL;
  739.     BundleTypePtr    theBundleType;
  740.     short            iconLocalID;
  741.     short            iconRsrcID;
  742.     OSType            iconRsrcType;
  743.     Handle            returnIconHandle;    
  744.     char            bndlState;
  745.     
  746.     *iconHandle = NULL;
  747.     
  748.     error = DetermineVRefNum(volName, vRefNum, &realVRefNum);
  749.     if ( error == noErr )
  750.     {
  751.         error = GetDesktopFileName(realVRefNum, desktopName);
  752.         if ( error == noErr )
  753.         {
  754.             savedResFile = CurResFile();
  755.         
  756.             /*
  757.             **    Open the 'Desktop' file in the root directory. (because
  758.             **    opening the resource file could preload unwanted resources,
  759.             **    bracket the call with SetResLoad(s))
  760.             */
  761.             SetResLoad(false);
  762.             dfRefNum = HOpenResFile(realVRefNum, fsRtDirID, desktopName, fsRdPerm);
  763.             SetResLoad(true);
  764.         
  765.             if ( dfRefNum != -1 )
  766.             {
  767.                 /*
  768.                 **    Find the BNDL resource with the specified creator.
  769.                 */
  770.                 error = FindBundleGivenCreator(fileCreator, &theBndl);
  771.                 if ( error == noErr )
  772.                 {
  773.                     /* Lock the BNDL resource so it won't be purged when other resources are loaded */
  774.                     bndlState = HGetState((Handle)theBndl);
  775.                     HLock((Handle)theBndl);
  776.                     
  777.                     /* Find the 'FREF' BundleType record in the BNDL resource. */
  778.                     error = FindTypeInBundle(kFREFResType, theBndl, &theBundleType);
  779.                     if ( error == noErr )
  780.                     {
  781.                         /* Find the local ID in the 'FREF' resource with the specified fileType */
  782.                         error = GetLocalIDFromFREF(theBundleType, fileType, &iconLocalID);
  783.                         if ( error == noErr )
  784.                         {
  785.                             /* Find the 'ICN#' BundleType record in the BNDL resource. */
  786.                             error = FindTypeInBundle(kIconFamResType, theBndl, &theBundleType);
  787.                             if ( error == noErr )
  788.                             {
  789.                                 /* Find the icon's resource ID in the 'ICN#' BundleType record */
  790.                                 error = GetIconRsrcIDFromLocalID(theBundleType, iconLocalID, &iconRsrcID);
  791.                                 if ( error == noErr )
  792.                                 {
  793.                                     /* Map Desktop Manager icon type to resource type */
  794.                                     iconRsrcType = DTIconToResIcon(iconType);
  795.                                     
  796.                                     if ( iconRsrcType != (OSType)0 )
  797.                                     {
  798.                                         /* Load the icon */
  799.                                         returnIconHandle = Get1Resource(iconRsrcType, iconRsrcID);
  800.                                         if ( returnIconHandle != NULL )
  801.                                         {
  802.                                             /* Copy the resource handle, and return the copy */
  803.                                             HandToHand(&returnIconHandle);
  804.                                             if ( MemError() == noErr )
  805.                                                 *iconHandle = returnIconHandle;
  806.                                             else
  807.                                                 error = afpItemNotFound;
  808.                                         }
  809.                                         else
  810.                                             error = afpItemNotFound;
  811.                                     }
  812.                                 }
  813.                             }
  814.                         }
  815.                     }
  816.                     /* Restore the state of the BNDL resource */ 
  817.                     HSetState((Handle)theBndl, bndlState);
  818.                 }
  819.                 /* Restore the resource chain and close the Desktop file */
  820.                 UseResFile(savedResFile);
  821.                 CloseResFile(dfRefNum);
  822.             }
  823.             else
  824.                 error = ResError(); /* could not open Desktop file */
  825.         }
  826.         if ( (error != noErr) && (error != memFullErr) )
  827.         {
  828.             error = afpItemNotFound;    /* force an error we should return */
  829.         }
  830.     }
  831.     
  832.     return ( error );
  833. }
  834.  
  835. /*****************************************************************************/
  836.  
  837. pascal    OSErr    DTGetIcon(StringPtr volName,
  838.                           short vRefNum,
  839.                           short iconType,
  840.                           OSType fileCreator,
  841.                           OSType fileType,
  842.                           Handle *iconHandle)
  843. {
  844.     OSErr error;
  845.     DTPBRec pb;
  846.     short dtRefNum;
  847.     Boolean newDTDatabase;
  848.     Size bufferSize;
  849.     
  850.     *iconHandle = NULL;
  851.     error = DTOpen(volName, vRefNum, &dtRefNum, &newDTDatabase);
  852.     if ( error == noErr )
  853.     {
  854.         /* there was a desktop database and it's now open */
  855.         
  856.         if ( !newDTDatabase )    /* don't bother to look in a new (empty) database */
  857.         {
  858.             /* get the buffer size for the requested icon type */
  859.             switch ( iconType )
  860.             {
  861.                 case kLargeIcon:
  862.                     bufferSize = kLargeIconSize;
  863.                     break;
  864.                 case kLarge4BitIcon:
  865.                     bufferSize = kLarge4BitIconSize;
  866.                     break;
  867.                 case kLarge8BitIcon:
  868.                     bufferSize = kLarge8BitIconSize;
  869.                     break;
  870.                 case kSmallIcon:
  871.                     bufferSize = kSmallIconSize;
  872.                     break;
  873.                 case kSmall4BitIcon:
  874.                     bufferSize = kSmall4BitIconSize;
  875.                     break;
  876.                 case kSmall8BitIcon:
  877.                     bufferSize = kSmall8BitIconSize;
  878.                     break;
  879.                 default:
  880.                     iconType = 0;
  881.                     bufferSize = 0;
  882.                     break;
  883.             }
  884.             if ( bufferSize != 0 )
  885.             {
  886.                 *iconHandle = NewHandle(bufferSize);
  887.                 if ( *iconHandle != NULL )
  888.                 {
  889.                     HLock(*iconHandle);
  890.         
  891.                     pb.ioDTRefNum = dtRefNum;
  892.                     pb.ioTagInfo = 0;
  893.                     pb.ioDTBuffer = **iconHandle;
  894.                     pb.ioDTReqCount = bufferSize;
  895.                     pb.ioIconType = iconType;
  896.                     pb.ioFileCreator = fileCreator;
  897.                     pb.ioFileType = fileType;
  898.                     error = PBDTGetIconSync(&pb);
  899.     
  900.                     HUnlock(*iconHandle);
  901.                     
  902.                     if ( error != noErr )
  903.                     {
  904.                         DisposeHandle(*iconHandle);    /* dispose of the allocated memory */
  905.                         *iconHandle = NULL;
  906.                     }
  907.                 }
  908.                 else
  909.                     error = memFullErr;    /* handle could not be allocated */
  910.             }
  911.             else
  912.                 error = paramErr;    /* unknown icon type requested */
  913.         }
  914.         else
  915.             error = afpItemNotFound;    /* the desktop database was empty - nothing to return */
  916.     }
  917.     else
  918.     {
  919.         /* There is no desktop database - try the Desktop file */
  920.         
  921.         error = GetIconFromDesktopFile(volName, vRefNum, iconType,
  922.                                         fileCreator, fileType, iconHandle);
  923.     }
  924.     
  925.     return ( error );
  926. }
  927.  
  928. /*****************************************************************************/
  929.  
  930. pascal    OSErr    DTSetComment(short vRefNum,
  931.                              long dirID,
  932.                              StringPtr name,
  933.                              ConstStr255Param comment)
  934. {
  935.     DTPBRec pb;
  936.     OSErr error;
  937.     short dtRefNum;
  938.     Boolean newDTDatabase;
  939.  
  940.     error = DTOpen(name, vRefNum, &dtRefNum, &newDTDatabase);
  941.     if ( error == noErr )
  942.     {
  943.         pb.ioDTRefNum = dtRefNum;
  944.         pb.ioNamePtr = name;
  945.         pb.ioDirID = dirID;
  946.         pb.ioDTBuffer = (Ptr)&comment[1];
  947.         /* Truncate the comment to 200 characters just in case */
  948.         /* some file system doesn't range check */
  949.         if ( comment[0] <= 200 )
  950.             pb.ioDTReqCount = comment[0];
  951.         else
  952.             pb.ioDTReqCount = 200;
  953.         error = PBDTSetCommentSync(&pb);
  954.     }
  955.     return (error);
  956. }
  957.  
  958. /*****************************************************************************/
  959.  
  960. pascal    OSErr    FSpDTSetComment(const FSSpec *spec,
  961.                               ConstStr255Param comment)
  962. {
  963.     return (DTSetComment(spec->vRefNum, spec->parID, (StringPtr)spec->name, comment));
  964. }
  965.  
  966. /*****************************************************************************/
  967.  
  968. /*
  969. **    GetCommentID
  970. **
  971. **    Get the comment ID number for the Desktop file's 'FCMT' resource ID from
  972. **    the file or folders fdComment (frComment) field.
  973. */
  974. static    OSErr    GetCommentID(short vRefNum,
  975.                              long dirID,
  976.                              StringPtr name,
  977.                              short *commentID)
  978. {
  979.     CInfoPBRec pb;
  980.     OSErr error;
  981.  
  982.     error = GetCatInfoNoName(vRefNum, dirID, name, &pb);
  983.     *commentID = pb.hFileInfo.ioFlXFndrInfo.fdComment;
  984.     return ( error );
  985. }
  986.  
  987. /*****************************************************************************/
  988.  
  989. /*
  990. **    GetCommentFromDesktopFile
  991. **
  992. **    Get a file or directory's Finder comment field (if any) from the
  993. **    Desktop file's 'FCMT' resources.
  994. */
  995. static    OSErr    GetCommentFromDesktopFile(short vRefNum,
  996.                                           long dirID,
  997.                                           StringPtr name,
  998.                                           Str255 comment)
  999. {
  1000.     OSErr error;
  1001.     short commentID;
  1002.     short realVRefNum;
  1003.     Str255 desktopName;
  1004.     short savedResFile;
  1005.     short dfRefNum;
  1006.     StringHandle commentHandle;
  1007.     
  1008.     /* Get the comment ID number */
  1009.     error = GetCommentID(vRefNum, dirID, name, &commentID);
  1010.     if ( error == noErr )
  1011.     {
  1012.         if ( commentID != 0 )    /* commentID == 0 means there's no comment */
  1013.         {
  1014.             error = DetermineVRefNum(name, vRefNum, &realVRefNum);
  1015.             if ( error == noErr )
  1016.             {
  1017.                 error = GetDesktopFileName(realVRefNum, desktopName);
  1018.                 if ( error == noErr )
  1019.                 {
  1020.                     savedResFile = CurResFile();
  1021.                     /*
  1022.                     **    Open the 'Desktop' file in the root directory. (because
  1023.                     **    opening the resource file could preload unwanted resources,
  1024.                     **    bracket the call with SetResLoad(s))
  1025.                     */
  1026.                     SetResLoad(false);
  1027.                     dfRefNum = HOpenResFile(realVRefNum, fsRtDirID, desktopName, fsRdPerm);
  1028.                     SetResLoad(true);
  1029.                     
  1030.                     if ( dfRefNum != -1)
  1031.                     {
  1032.                         /* Get the comment resource */
  1033.                         commentHandle = (StringHandle)Get1Resource(kFCMTResType,commentID);
  1034.                         if ( commentHandle != NULL )
  1035.                         {
  1036.                             if ( GetHandleSize((Handle)commentHandle) > 0 )
  1037.                                 BlockMoveData(*commentHandle, comment, *commentHandle[0] + 1);
  1038.                             else
  1039.                                 error = afpItemNotFound;    /* no comment available */
  1040.                         }
  1041.                         else
  1042.                             error = afpItemNotFound;    /* no comment available */
  1043.                         
  1044.                         /* restore the resource chain and close the Desktop file */
  1045.                         UseResFile(savedResFile);
  1046.                         CloseResFile(dfRefNum);
  1047.                     }
  1048.                     else
  1049.                         error = afpItemNotFound;
  1050.                 }
  1051.                 else
  1052.                     error = afpItemNotFound;
  1053.             }
  1054.         }
  1055.         else
  1056.             error = afpItemNotFound;    /* no comment available */
  1057.     }
  1058.     
  1059.     return ( error );
  1060. }
  1061.  
  1062. /*****************************************************************************/
  1063.  
  1064. pascal    OSErr    DTGetComment(short vRefNum,
  1065.                              long dirID,
  1066.                              StringPtr name,
  1067.                              Str255 comment)
  1068. {
  1069.     DTPBRec pb;
  1070.     OSErr error;
  1071.     short dtRefNum;
  1072.     Boolean newDTDatabase;
  1073.  
  1074.     if (comment != NULL)
  1075.     {
  1076.         comment[0] = 0;    /* return nothing by default */
  1077.         
  1078.         /* attempt to open the desktop database */
  1079.         error = DTOpen(name, vRefNum, &dtRefNum, &newDTDatabase);
  1080.         if ( error == noErr )
  1081.         {
  1082.             /* There was a desktop database and it's now open */
  1083.             
  1084.             if ( !newDTDatabase )
  1085.             {
  1086.                 pb.ioDTRefNum = dtRefNum;
  1087.                 pb.ioNamePtr = name;
  1088.                 pb.ioDirID = dirID;
  1089.                 pb.ioDTBuffer = (Ptr)&comment[1];
  1090.                 error = PBDTGetCommentSync(&pb);
  1091.                 if (error == noErr)
  1092.                     comment[0] = (unsigned char)pb.ioDTActCount;
  1093.             }
  1094.         }
  1095.         else
  1096.         {
  1097.             /* There is no desktop database - try the Desktop file */
  1098.             error = GetCommentFromDesktopFile(vRefNum, dirID, name, comment);
  1099.             if ( error != noErr )
  1100.                 error = afpItemNotFound;    /* return an expected error */
  1101.         }
  1102.     }
  1103.     else
  1104.         error = paramErr;
  1105.     
  1106.     return (error);
  1107. }
  1108.  
  1109. /*****************************************************************************/
  1110.  
  1111. pascal    OSErr    FSpDTGetComment(const FSSpec *spec,
  1112.                               Str255 comment)
  1113. {
  1114.     return (DTGetComment(spec->vRefNum, spec->parID, (StringPtr)spec->name, comment));
  1115. }
  1116.  
  1117. /*****************************************************************************/
  1118.  
  1119. pascal    OSErr    DTCopyComment(short srcVRefNum,
  1120.                               long srcDirID,
  1121.                               StringPtr srcName,
  1122.                               short dstVRefNum,
  1123.                               long dstDirID,
  1124.                               StringPtr dstName)
  1125. /* The destination volume must support the Desktop Manager for this to work */
  1126. {
  1127.     OSErr error;
  1128.     Str255 comment;
  1129.  
  1130.     error = DTGetComment(srcVRefNum, srcDirID, srcName, comment);
  1131.     if ( (error == noErr) && (comment[0] > 0) )
  1132.     {
  1133.         error = DTSetComment(dstVRefNum, dstDirID, dstName, comment);
  1134.     }
  1135.     return (error);
  1136. }
  1137.  
  1138. /*****************************************************************************/
  1139.  
  1140. pascal    OSErr    FSpDTCopyComment(const FSSpec *srcSpec,
  1141.                                const FSSpec *dstSpec)
  1142. /* The destination volume must support the Desktop Manager for this to work */
  1143. {
  1144.     return (DTCopyComment(srcSpec->vRefNum, srcSpec->parID, (StringPtr)srcSpec->name,
  1145.                         dstSpec->vRefNum, dstSpec->parID, (StringPtr)dstSpec->name));
  1146. }
  1147.  
  1148. /*****************************************************************************/
  1149.